﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Refl.Dreaming
{
    /// <summary>
    /// Wrap the code into a class and namespace.
    /// </summary>
    internal static class Encapsulate
    {
        static internal string CSharp(Dream d)
        {
            //Generate the usings
            List<String> Usings = DreamInfo.DefaultNamespacesFor(d.Info.DreamType);
            string ulist = "";
            foreach (string Using in Usings)
            {
                ulist += "using " + Using + ";\n";
            }
            //generate the variables declaration
            string vlist = "";
            foreach (Var v in d._Vars)
            {
                vlist += "public " + v.Object.GetType().FullName + " " + v.Name + ";\n";
            }

            StringBuilder model = new StringBuilder();
            model.Append(ulist);//Adds the using directives
            model.Append("namespace N_" + d.Info.Name + "\n{\n");
            model.Append("public class C_" + d.Info.Name + "\n{\n");
            model.Append(vlist);
            model.Append("public void DreamMain()\n{\n" + d._Str_Code + "\n}\n}\n}");

            return model.ToString();
        }
        static internal string VisualBasic(Dream d)
        {
            string code = d._Str_Code;
            List<String> Usings = DreamInfo.DefaultNamespacesFor(d.Info.DreamType);
            string ulist = "";
            foreach (string Using in Usings)
            {
                ulist += "Imports " + Using + "\n";
            }
            string vlist = "";
            foreach (Var v in d._Vars)
            {
                vlist += "Public " + v.Name + " as " + v.Object.GetType().FullName + "\n";
            }
            StringBuilder model = new StringBuilder();
            model.Append(ulist);//Adds the using directives
            model.Append("Namespace N_" + d.Info.Name + "\n");
            model.Append("Public Class C_" + d.Info.Name + "\n");
            model.Append(vlist);
            model.Append("Public Sub DreamMain()\n" + d._Str_Code + "\nEnd Sub\nEnd Class\nEnd Namespace");

            return model.ToString();
        }
        //TODO: as soon as string implementation is dropped this method MUST be updated, since RCS -> CS would be a workaround
        static internal string ReflectiveCSharp(Dream d)
        {
            return CSharp(d);
        }
        static internal string JScript(Dream d)
        {
            //Generate the usings
            List<String> Usings = DreamInfo.DefaultNamespacesFor(d.Info.DreamType);
            string ulist = "";
            foreach (string Using in Usings)
            {
                ulist += "import " + Using + ";\n";
            }
            //generate the variables declaration
            string vlist = "";
            foreach (Var v in d._Vars)
            {
                vlist += "public var " + v.Name + ";\n";
            }

            StringBuilder model = new StringBuilder();
            model.Append(ulist);//Adds the using directives
            model.Append("public class C_" + d.Info.Name + "\n{\n");
            model.Append(vlist);
            model.Append("public function DreamMain()\n{\n" + d._Str_Code + "\n}\n}");

            return model.ToString();
        }
        static internal string CPlusPlus(Dream d)
        {
            List<string> References = d.Info.AssemblyReferences;
            string rlist = "";
            foreach (string Reference in References)
            {
                rlist += "#using<" + Reference + ">\n";
            }
            List<String> Usings = DreamInfo.DefaultNamespacesFor(d.Info.DreamType);
            string ulist = "";
            foreach (string Using in Usings)
            {
                ulist += "using namespace " + Using.Replace(".", "::") + ";\n";
            }
            //generate the variables declaration
            string vlist = "";
            foreach (Var v in d._Vars)
            {
                vlist += v.Object.GetType().FullName.Replace(".","::") + "^ " + v.Name + ";\n";
            }

            StringBuilder model = new StringBuilder();
            model.AppendLine(rlist);
            model.Append(ulist);//Adds the using directives
            model.Append("namespace N_" + d.Info.Name + "\n{\n");
            model.Append("public ref class C_" + d.Info.Name + "\n{\npublic:\n");
            model.Append(vlist);
            model.Append("public:\n void DreamMain()\n{\n" + d._Str_Code + "\n}\n};\n}");

            return model.ToString();
        }
        internal static string IL(Dream d)
        {
            List<String> References = d.Info.AssemblyReferences;
            string rlist = "";
            foreach (string Reference in References)
            {
                string s = Path.GetFileNameWithoutExtension(Reference);
                rlist += ".assembly extern " + s + " {\n  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )\n  .ver 4:0:0:0\n}\n";


            }

            StringBuilder model = new StringBuilder();

            model.Append(rlist);
            model.Append(".assembly A_" + d.Info.Name + " {}\n");
            model.Append(".namespace N_" + d.Info.Name + "\n{\n");
            model.Append(".class C_" + d.Info.Name + " extends [mscorlib]System.Object\n{\n");
            model.Append(".method public void DreamMain() cil managed\n{\n" + d._Str_Code + "}\n}\n}\n");

            return model.ToString();
        }
        internal static string FSharp(Dream d)
        {
            //Generate the usings
            List<String> Usings = DreamInfo.DefaultNamespacesFor(d.Info.DreamType);
            string ulist = "";
            foreach (string Using in Usings)
            {
                ulist += "open " + Using + "\n";
            }
            //generate the variables declaration
            string vlist = "";
            foreach (Var v in d._Vars)
            {
                //TODO: having trouble implementing object insertion at F#
                //Two spaces must exist before the member declaration (F# identation)
                vlist += "  member x. " + v.Object.GetType().FullName + " " + v.Name + "\n";
            }

            StringBuilder model = new StringBuilder();
            model.Append("namespace N_" + d.Info.Name + "\n");
            model.Append(ulist);//Adds the using directives
            //one space must exist before the class declaration (F# identation)
            model.Append(" type C_" + d.Info.Name + "() = class\n");
            //model.Append(vlist);
            string idented = ("   "+d._Str_Code).Replace("\n","   \n");
            model.Append("  member self.DreamMain() = \n" + idented + "\n end\n");

            return model.ToString();
        }
    }
}
